import struct


class HNParsePage(object):
    def __init__(self, data, old_style=False):
        self.data = data
        self.data_length = len(data)
        self.characters = []
        self.figures = []
        self.stats = {}
        self.offset = 0

        def Text(self, code):
            try:
                self.characters.append(bytes([self.data[self.offset + 5], self.data[self.offset + 4]]).decode("gbk"))
            except IndexError:  # short data, nothing to do
                pass
            except UnicodeDecodeError:
                # HTL: When cut-and-paste on Linux, these transform to GB18030,
                # but I believe they are OCR artifacts. Where they occur,
                # 0xA38D 0xA38a (always together) are line-breaks, and 0xA389, 0xA3A0
                # are tabs and spaces.
                hash = {
                    0xA389: "\t",
                    0xA38a: "\n",
                    0xA38D: "\r",
                    0xA3A0: " ",
                    # # GB18030
                    # 0xA389 : "",
                    # 0xA38a : "",
                    # 0xA38D : "",
                    # 0xA3A0 : "",
                }
                code = self.data[self.offset + 5] * 256 + self.data[self.offset + 4]
                try:
                    # self.characters.append("<0x%04X>\n" % code)
                    self.characters.append(hash[code])
                except KeyError:
                    self.characters.append("<0x%04X>\n" % code)
            self.offset += 6

        def TextMulti(self, code):
            self.offset += 2
            if (code == 0x8001):
                self.characters.append("\n")
            while (1):
                try:
                    if (self.data[self.offset + 1] == 0x80):
                        break
                except IndexError:  # short data, nothing to do
                    return
                try:
                    self.characters.append(
                        bytes([self.data[self.offset + 3], self.data[self.offset + 2]]).decode("gbk"))
                except UnicodeDecodeError:
                    self.characters.append(
                        "<0x%04X>\n" % (self.data[self.offset + 3] * 256 + self.data[self.offset + 2]))
                except IndexError:  # short data, nothing to do
                    return
                self.offset += 4

        def Figure(self, code):
            try:
                self.data[self.offset + 25]
            except IndexError:  # short data, nothing to do
                return
            (ignore1, offset_x, offset_y, size_x, size_y, int2, int3, int4, int5) = struct.unpack("<HHHHHIIII",
                                                                                                  self.data[
                                                                                                  self.offset:self.offset + 26])
            # in units of 1/2.473 pixels
            self.figures.append([offset_x, offset_y, size_x, size_y])
            self.offset += 26

        if (not old_style):
            dispatch = {
                0x8001: Text,
                0x800A: Figure,
            }
        else:
            dispatch = {
                0x8001: TextMulti,
                0x8070: TextMulti,
                0x800A: Figure,
            }
        dispatch_keys = dispatch.keys()

        while (self.offset <= self.data_length - 2):
            (dispatch_code,) = struct.unpack("H", self.data[self.offset:self.offset + 2])
            self.offset += 2
            if (dispatch_code in dispatch_keys):
                dispatch[dispatch_code](self, dispatch_code)
            else:
                self.offset += 2
                if (dispatch_code in self.stats.keys()):
                    self.stats[dispatch_code] += 1
                else:
                    self.stats[dispatch_code] = 1

    @property
    def texts(self):
        text = ''.join(self.characters)
        text.replace('\x00', '')
        text.replace('\r', '')
        return text
